/*
 * Proto Streamer
 * Copyright (C) 2009 John Pritchard.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */
package p.s.t;

import p.s.m.Consumer;
import p.s.m.Producer;
import com.google.protobuf.Message;
import java.lang.reflect.InvocationTargetException;

/**
 * A session- mapped value. 
 * 
 * Some applications work well with a session- named value to which
 * uplinks update, and from which downlinks copy.
 * 
 * @author jdp
 */
public class Slot
    extends p.s.m.Base
{
    /**
     * Slot constructor used by map manager.
     */
    public final static class Constructor
        extends Object
    {
        public final Class<? extends Slot> clas;

        public final java.lang.reflect.Constructor<? extends Slot> ctor;

        public Constructor(Class<? extends Slot> clas)
            throws NoSuchMethodException
        {
            super();
            assert null != clas;
            this.clas = clas;
            this.ctor = clas.getConstructor(Object.class);
            assert null != this.ctor;
        }

        public Slot newInstance(Object id)
            throws InstantiationException, IllegalAccessException,
                   IllegalArgumentException, InvocationTargetException
        {
            return this.ctor.newInstance(id);
        }
    }


    protected volatile Message message;


    public Slot(Object id){
        super(id);
    }


    protected Message update(Consumer c){
        this.lock.lockReadEnter();
        try {
            Message m = this.message;
            if (null != m){
                int p = c.getServicePointer(this.identity,this.version);
                if (0 == p){
                    c.setServicePointer(this.identity,this.version,(1));
                    return m;
                }
            }
            return null;
        }
        finally {
            this.lock.lockReadExit();
        }
    }
    public void update(Producer p, Message m){
        if (null != m){
            this.lock.lockWriteEnter();
            try {
                this.message = m;
                this.version++;
            }
            finally {
                this.lock.lockWriteExit();
            }
            synchronized(this.monitor){
                this.monitor.notifyAll();
            }
        }
        else
            throw new IllegalArgumentException("Null message");
    }
    public void clear(Producer p){
        this.lock.lockWriteEnter();
        try {
            this.message = null;
            this.version++;
        }
        finally {
            this.lock.lockWriteExit();
        }
    }
    public boolean hasExpired(){
        return false;
    }
    public void init(){
    }
    public void destroy(){
    }
}
